import re
import glob
import os
import sys
from PySide6.QtGui import *
from PySide6.QtWidgets import *
from PySide6.QtCore import *
import csv
import chardet

def app_path():
    if hasattr(sys, 'frozen'):  
        return os.path.abspath(sys.executable)
    return os.path.abspath(__file__) 

class OpenFolderWidget(QWidget):
    def __init__(self, title: str):
        super().__init__()
        self.label = QLabel(title)
        self.edit = QLineEdit()
        self.button_open = QPushButton('open')
        self.layout = QHBoxLayout(self)
        self.layout.addWidget(self.label)
        self.layout.addWidget(self.edit)
        self.layout.addWidget(self.button_open)
        self.edit.setReadOnly(True)

class ProgressBarWidget(QWidget):
    def __init__(self, title: str):
        super().__init__()
        self.label = QLabel(title)
        self.button_start = QPushButton('start')
        self.progress_bar = QProgressBar()
        self.progress_bar.setValue(0)
        self.layout = QHBoxLayout(self)
        self.layout.addWidget(self.label)
        self.layout.addWidget(self.progress_bar)
        self.layout.addWidget(self.button_start)

class CodeCheckView(QWidget):
    signal_folder = Signal(str)
    signal_currentfile = Signal(str)
    def __init__(self):
        super().__init__()
        self.gtr_workbook_events = None
        self.code_path = OpenFolderWidget('Code path:   ')
        self.progress = ProgressBarWidget('Progress bar:')
        input_layout = QVBoxLayout()
        input_layout.addWidget(self.code_path)
        input_layout.addWidget(self.progress)
        group_box_input = QGroupBox('')
        group_box_input.setLayout(input_layout)
        tab_layout = QVBoxLayout()
        tab_layout.addWidget(group_box_input)
        self.setLayout(tab_layout)
        self.setWindowTitle("Code check")
        self.resize(600, 300)
        self.show()

        self.code_path.button_open.clicked.connect(self.SlotChooseFolder)
        self.progress.button_start.clicked.connect(self.TraversalFolder)

    def ProgressBar(self, check_process): 
        self.progress.progress_bar.setValue(check_process)
        QCoreApplication.processEvents()

    def SlotChooseFolder(self): # open
        folder_path = QFileDialog.getExistingDirectory(self)
        self.code_path.edit.setText(folder_path)
        self.signal_folder = folder_path

    def TraversalFolder(self): # start
        folder_path = self.signal_folder
        for filename in glob.glob(f'{folder_path}/**/*',recursive=True):
            if ".cpp" in filename:
                self.signal_currentfile = filename
                print(filename)
                main(filename) # guofeng
            self.ProgressBar((glob.glob(f'{folder_path}/**/*',recursive=True).index(filename)+1)/len(glob.glob(f'{folder_path}/**/*',recursive=True)) * 100)

def export_to_csv(data, filename):
    with open(filename, 'a', newline='', encoding='utf-8') as csvfile:
        writer = csv.writer(csvfile)
        writer.writerows(data)               

def find_draw_watch_tbl_definitions(file_content):
    new_list = []
    pattern = re.compile(r'const\s+UC\s*\*\s*const\s*\w*Draw_Watch\w*Tbl\s*\[\s*\]\s*=\s*\{([^}]+)\};',re.IGNORECASE)
    match = pattern.findall(file_content)
    if not match:
        # raise ValueError("DrawWatchTbl definition not found in the file.")
        print(("DrawWatchTbl definition not found in the file."))
    for res in match:
        pattern = re.compile(r'&VH_ucRcvDataUpdate\[R_FUNC_(\w+)\]')
        matches = pattern.findall(res)
        for res in matches:
            new_list.append(res)
    # print(new_list)
    return new_list

def find_switch_statements(file_content):
    new_list=[]
    pattern = re.compile(r'switch\s*\(\s*RcvData_(\w+)\.\w+\s*\)')
    matches = pattern.findall(file_content)
    uppercase_list = list(map(str.upper, matches))
    for item in uppercase_list :
        new_list.append(item)
    # print("find_switch_statements")
    # print(new_list)
    return new_list

def check_elements_in_lists(list1, list2, cpp_file_path):
    current_directory = os.getcwd()
    error_file = os.path.join(current_directory, "check_draw_watch_tbl_error.csv")
    new_list1 = []
    for element in list1:
        # print(element)
        new_list1.append(str(element).replace("_",""))
        if str(element).replace("_","") not in list2:
            data_tmp = "No definition matched for R_FUNC_" + element + " and switch RcvData_" + element + " was found"
            data = [[cpp_file_path, data_tmp]]
            print(f"{data}")
            export_to_csv(data,error_file)
    # print(list1)
    # print(new_list1)
    for element in list2:
        # print(element)
        if element not in new_list1:
            data_tmp = "No definition matched for switch RcvData_" + element + " and R_FUNC_" + element + " was found"
            data = [[cpp_file_path, data_tmp]]
            print(f"{data}")
            export_to_csv(data,error_file)

def main(cpp_file_path):
    with open(cpp_file_path, 'rb') as f:
        raw_data = f.read()
        result = chardet.detect(raw_data)
        encoding = result['encoding']
    with open(cpp_file_path, 'r' , encoding=encoding) as file:
        file_content = file.read()
        #print(file_content)
    list1 = find_draw_watch_tbl_definitions(file_content)

    list2 = find_switch_statements(file_content)

    check_elements_in_lists(list1, list2, cpp_file_path)


if __name__ == "__main__":
    current_directory = os.getcwd()
    error_file = os.path.join(current_directory, "check_draw_watch_tbl_error.csv")
    if os.path.exists(error_file):
        os.remove(error_file)
    data = [["CPP file path", "Error description"]]
    # print(f"{data}")
    export_to_csv(data,error_file)

    app = QApplication([])
    window = CodeCheckView()
    app.exec()
